/*
 * @Description: 部门service
 * @Author: Haor
 * @Date: 2022-05-16 14:30:27
 * @LastEditTime: 2022-05-16 14:34:38
 * @LastEditors: Haor
 */
import { Injectable } from '@nestjs/common'
import { HttpResTemplate, HttpResult } from "@libs/http.result";
import { InjectRepository } from "@nestjs/typeorm";
import { DepartmentEntity } from "@entities/department.entity";
import { Repository } from "typeorm";
import { listToTree } from "@utils/data";
import { BusinessException, ParamsException } from "@exceptions";
import { CreateDepartmentDto } from "@dto/department.dto";
import { format } from "@utils/date";
import { SnowflakeId } from "@libs/snowflake.id";

@Injectable()
export class DepartmentService {
    constructor(
        @InjectRepository(DepartmentEntity)
        private readonly deptRepository: Repository<DepartmentEntity>
    ) {
    }

    /**
     * 验证名称是否重复
     * @param {number} pid
     * @param {string} name
     * @private
     */
    private async checkName(pid: number, name: string) {
        const find = await this.deptRepository.findOne({
            where: { pid, name, isDelete: 0 }
        })
        return Promise.resolve(!!find)
    }

    /**
     * 验证部门是否存在
     * @param {number} id
     * @private
     */
    private async checkDeptIsExist(id) {
        return this.deptRepository.findOne({ where: {id, isDelete: 0} })
    }

    /**
     * 创建部门
     * @param {number} pid
     * @param {CreateDepartmentDto} data
     */
    async createDept(pid: number, data: CreateDepartmentDto): Promise<HttpResTemplate> {
        const checkExist = await this.checkName(pid, data.name);
        if (checkExist) {
            throw new BusinessException('名称重复')
        }
        // 判断pid是否存在
        if (pid !== 0 && !await this.checkDeptIsExist(pid)) {
            throw new ParamsException()
        }
        const newDept: DepartmentEntity = this.deptRepository.create(data)
        newDept.id = SnowflakeId.generate()
        newDept.pid = pid
        newDept.createTime = format(Date.now())
        newDept.createBy = 'admin'
        const res = await this.deptRepository.save(newDept)
        return HttpResult.success(res)
    }

    /**
     * 获取部门列表
     */
    async getDeptList(): Promise<HttpResTemplate> {
        return HttpResult.success()
    }

    /**
     * 通过父级id获取下级
     * @param {number} pid
     */
    async getDeptListByParentId(pid): Promise<HttpResTemplate> {
        const deptList = await this.deptRepository.find({ where: { isDelete: 0 }})
        const deptMap = new Map() // 统计每个下面的子集数量
        for (let i = 0, len = deptList.length; i < len; i++) {
            const dept = deptList[i];
            if (!deptMap.has(dept.pid)) {
                deptMap.set(dept.pid, 0)
            }
            const count = deptMap.get(dept.pid)
            deptMap.set(dept.pid, Number(count)+1)
        }

        // 过滤出pid相同的部门
        const filterMenuList = deptList.reduce((res: Array<DepartmentEntity>, menu: DepartmentEntity) => {
            // 与pid相同的
            if (+menu.pid === pid) {
                menu['hasChildren'] = !!+deptMap.get(menu.id) // 是否存在下级
                res.push(menu)
            }
            return res
        }, [])

        return HttpResult.success(filterMenuList)
    }

    /**
     * 获取部门树
     */
    async getDeptTree(): Promise<HttpResTemplate> {
        const deptList = await this.deptRepository.find({ where: { isDelete: 0 }});
        const deptTree = listToTree(deptList, '0');
        return HttpResult.success(deptTree)
    }

    /**
     * 根据id删除部门
     * @param {number} id 部门id
     */
    async deleteDeptById(id): Promise<HttpResTemplate> {
        if (!id) throw new ParamsException()
        const find = await this.deptRepository.findOne({ where: { id: id } })
        if (!find) {
            throw new ParamsException()
        }
        await this.deptRepository.update({id: id}, {isDelete: 1})
        return HttpResult.success()
    }
}
